﻿using NDF;
using NDF.Collections;
using NDF.Collections.Generic;
using NDF.ComponentModel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.Linq
{
    /// <summary>
    /// 为常见的快速操作 <see cref="System.Collections.IEnumerable"/> 序列对象操作提供实用工具方法。
    /// </summary>
    public static partial class EnumerableHelper
    {
        public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
        {
            foreach (var item in source)
            {
                yield return (TResult)item;
            }
        }

        public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source, Converter<object, TResult> converter)
        {
            foreach (var item in source)
            {
                yield return converter.Invoke(item);
            }
        }




        public static bool Contains(this IEnumerable source, object item)
        {
            return Contains(source, item, EqualityComparer.Default);
        }

        public static bool Contains(this IEnumerable source, object item, IEqualityComparer comparer)
        {
            var array = source.ToArray<object>();
            return System.Linq.Enumerable.Contains(array, item, comparer.ToGeneric());
        }




        /// <summary>
        /// 返回序列中的元素数量。
        /// </summary>
        /// <param name="source">包含要计数的元素的序列。</param>
        /// <returns>输入序列中的元素数量。</returns>
        public static int Count(this IEnumerable source)
        {
            return ToGeneric(source).Count();
        }

        /// <summary>
        /// 返回一个数字，表示在指定的序列中满足条件的元素数量。
        /// </summary>
        /// <param name="source">包含要测试和计数的元素的序列。</param>
        /// <param name="predicate">用于测试每个元素是否满足条件的函数。</param>
        /// <returns>一个数字，表示序列中满足谓词函数条件的元素数量。</returns>
        public static int Count(this IEnumerable source, Func<object, bool> predicate)
        {
            return ToGeneric(source).Count(predicate);
        }



        /// <summary>
        /// 返回一个序列 <see cref="System.Collections.Generic.IEnumerable"/> ，它是源序列中的一个子集。
        /// </summary>
        /// <param name="source">源序列对象。</param>
        /// <param name="startIndex">返回剩余元素前要跳过的元素数量，也可理解为范围开始处的从零开始的 <see cref="System.Collections.Generic.IEnumerable"/> 索引。</param>
        /// <returns><see cref="System.Collections.Generic.IEnumerable"/>，它表示源 <see cref="System.Collections.Generic.IEnumerable"/> 中元素的子集。</returns>
        public static IEnumerable GetRange(this IEnumerable source, int startIndex)
        {
            return ToGeneric(source).GetRange(startIndex);
        }

        /// <summary>
        /// 返回一个序列 <see cref="System.Collections.Generic.IEnumerable"/> ，它是源序列中的一个子集。
        /// </summary>
        /// <param name="source">源序列对象。</param>
        /// <param name="startIndex">返回剩余元素前要跳过的元素数量，也可理解为范围开始处的从零开始的 <see cref="System.Collections.Generic.IEnumerable"/> 索引。</param>
        /// <param name="count">范围中的元素数，同时也表示要返回的元素数量。</param>
        /// <returns><see cref="System.Collections.Generic.IEnumerable"/>，它表示源 <see cref="System.Collections.Generic.IEnumerable"/> 中元素的子集。</returns>
        public static IEnumerable GetRange(this IEnumerable source, int startIndex, int count)
        {
            return ToGeneric(source).GetRange(startIndex, count);
        }




        /// <summary>
        /// 返回序列中指定索引处的元素。
        /// </summary>
        /// <param name="source">要从中返回元素的 <see cref="System.Collections.IEnumerable"/>。</param>
        /// <param name="index">要检索的从零开始的元素索引。</param>
        /// <returns>源序列中指定位置处的元素。</returns>
        public static object Get(this IEnumerable source, int index)
        {
            return ToGeneric(source).Get(index);
        }

        /// <summary>
        /// 返回序列中指定索引处的元素；如果索引超出范围，则返回默认值。
        /// </summary>
        /// <param name="source">要从中返回元素的 <see cref="System.Collections.Generic.IEnumerable"/>。</param>
        /// <param name="index">要检索的从零开始的元素索引。</param>
        /// <returns>如果索引超出源序列的范围，则为 default(object) / null；否则为源序列中指定位置处的元素。</returns>
        public static object GetOrDefault(this IEnumerable source, int index)
        {
            return ToGeneric(source).GetOrDefault(index);
        }




        /// <summary>
        /// 反转序列中元素的顺序。
        /// </summary>
        /// <param name="source">要反转的值序列。</param>
        /// <returns>一个序列，其元素以相反顺序对应于输入序列的元素。</returns>
        public static IEnumerable Reverse(this IEnumerable source)
        {
            return ToGeneric(source).Reverse();
        }




        public static object[] ToArray(this IEnumerable source)
        {
            return ToGeneric(source).ToArray();
        }

        public static TResult[] ToArray<TResult>(this IEnumerable source)
        {
            return Cast<TResult>(source).ToArray();
        }




        public static List<object> ToList(this IEnumerable source)
        {
            return ToGeneric(source).ToList();
        }




        /// <summary>
        /// 根据指定类型筛选 <see cref="System.Collections.IEnumerable"/> 的元素。
        /// </summary>
        /// <param name="source"><see cref="System.Collections.IEnumerable"/>，其元素用于筛选。</param>
        /// <param name="c">筛选序列元素所根据的类型。</param>
        /// <returns>一个 <see cref="System.Collections.IEnumerable"/>，包含类型为 c 的输入序列中的元素。</returns>
        public static IEnumerable OfType(this IEnumerable source, Type c)
        {
            return OfType(source, c, true);
        }

        /// <summary>
        /// 根据指定类型筛选 <see cref="System.Collections.IEnumerable"/> 的元素。
        /// </summary>
        /// <param name="source"><see cref="System.Collections.IEnumerable"/>，其元素用于筛选。</param>
        /// <param name="c">筛选序列元素所根据的类型。</param>
        /// <param name="inherit">值为 true 时指定返回序列中每个元素的类型可以是 c 的子类或接口实现类，值为 false 时指示每个元素的类型必须等同于 c；</param>
        /// <returns>一个 <see cref="System.Collections.IEnumerable"/>，包含类型为 c 的输入序列中的元素。</returns>
        public static IEnumerable OfType(this IEnumerable source, Type c, bool inherit)
        {
            return ToGeneric(source).Where(item =>
            {
                return item == null ? false : (item.GetType() == c || (inherit && c.IsInstanceOfType(item)));
            });
        }

        /// <summary>
        /// 根据指定类型筛选 <see cref="System.Collections.IEnumerable"/> 的元素。
        /// </summary>
        /// <typeparam name="TResult">筛选序列元素所根据的类型。</typeparam>
        /// <param name="source"><see cref="System.Collections.IEnumerable"/>，其元素用于筛选。</param>
        /// <param name="inherit">值为 true 时指定返回序列中每个元素的类型可以是 c 的子类或接口实现类，值为 false 时指示每个元素的类型必须等同于 c；该值默认为 true。</param>
        /// <returns>一个 <see cref="System.Collections.IEnumerable"/>，包含类型为 c 的输入序列中的元素。</returns>
        public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source, bool inherit)
        {
            return inherit ? source.OfType<TResult>() : Cast<TResult>(OfType(source, typeof(TResult), inherit));
        }





        public static void XXX(this IEnumerable source)
        {
            //source.Contains
            //source.ToList().LastIndexOf
        }

        public static void XXX<TSource>(this IEnumerable<TSource> source)
        {
            //source.re
        }




        /// <summary>
        /// 基于谓词筛选值序列。
        /// </summary>
        /// <param name="source">要筛选的 <see cref="System.Collections.IEnumerable"/>。</param>
        /// <param name="predicate">用于测试每个元素是否满足条件的函数。</param>
        /// <returns>一个 <see cref="System.Collections.IEnumerable"/>，包含输入序列中满足条件的元素。</returns>
        public static IEnumerable Where(this IEnumerable source, Func<object, bool> predicate)
        {
            return ToGeneric(source).Where(predicate);
        }

        /// <summary>
        /// 基于谓词筛选值序列。 将在谓词函数的逻辑中使用每个元素的索引。
        /// </summary>
        /// <param name="source">要筛选的 <see cref="System.Collections.IEnumerable"/>。</param>
        /// <param name="predicate">用于测试每个源元素是否满足条件的函数；该函数的第二个参数表示源元素的索引。</param>
        /// <returns>一个 <see cref="System.Collections.IEnumerable"/>，包含输入序列中满足条件的元素。</returns>
        public static IEnumerable Where(this IEnumerable source, Func<object, int, bool> predicate)
        {
            return ToGeneric(source).Where(predicate);
        }







        /// <summary>
        /// 判断序列对象是否为 Null 或者其中不包含任何元素。
        /// </summary>
        /// <param name="source">被判断的序列对象。</param>
        /// <returns>如果序列对象为 Null 或者其中不包含任何元素，则返回 true，否则返回 false。</returns>
        public static bool IsNullOrEmpty(this IEnumerable source)
        {
            return source == null || source.ToArray().Length == 0;
        }


        /// <summary>
        /// 将一个 普通枚举序列 <see cref="System.Collections.Generic.IEnumerable"/> 转换成一个泛型枚举序列 <see cref="System.Collections.Generic.IEnumerable(Of Object)"/>。
        /// </summary>
        /// <typeparam name="TSource">source 中的元素的类型。</typeparam>
        /// <param name="source">被转换的普通枚举序列 <see cref="System.Collections.Generic.IEnumerable"/> 对象。</param>
        /// <returns>一个 <see cref="System.Collections.Generic.IEnumerable(Of Object)"/>，包含输入序列中所有的元素。</returns>
        public static IEnumerable<object> ToGeneric(this IEnumerable source)
        {
            foreach (var item in source)
            {
                yield return item;
            }
        }

    }
}


namespace NDF.Collections
{
    /// <summary>
    /// 为常见的快速构建或封装 IEnumerable 对象操作提供实用工具方法。
    /// </summary>
    public static class EnumerableHelper
    {
        /// <summary>
        /// 将对象构建成一个序列 <see cref="System.Collections.Generic.IEnumerable(TSource)"/> 并返回。
        /// </summary>
        /// <typeparam name="TSource">表示对象的类型，也即是返回的泛型序列中元素的类型。</typeparam>
        /// <param name="item">待返回序列中包含的元素.</param>
        /// <returns>返回一个新创建的序列，该序列中包含一个元素即是 item。</returns>
        public static IEnumerable<TSource> ToEnumerable<TSource>(this TSource item)
        {
            yield return item;
        }
    }
}